/***********************************************************
 *  File_Name  : XJRWLock.h
 *  File_Path   :
 *  File_Encode : UTF8
 *  Description : 线程读写锁
 *
 *  OS : Linux, UNIX, Windows
 *  LastVersion  : 20140820
 *
 *  Author      : LiXiujie(李秀杰)
 *  Date        : 2014-8-20
 *  Version     : 20140820
 *  Description :
 *
 *  Edit Author :
 *  Edit Date   :
 *  Version     :
 *  Description :
 *
 ***********************************************************/
#ifndef XJRWLOCK_H_
#define XJRWLOCK_H_

#include "XJEnv.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdexcept>
#include <sys/syscall.h>
#include "XJMutex.h"
#include "XJSemaphore.h"

namespace XJUtilClass {

class XJRWLock {
public:
	XJRWLock();
	virtual ~XJRWLock();

public:
	void WaitToRead();
	void WaitToWrite();
	void ReadDone();
	void WriteDone();

private:
	void Done			(XJSemaphore** ppSem, short& lCount);
#ifndef _WIN32
	bool IsOwner()		{return m_dwWriterTID == GetCurrTID();}
#else
	BOOL IsOwner()		{return m_dwWriterTID == GetCurrTID();}
#endif
	void SetOwner()		{m_dwWriterTID = GetCurrTID();}
	void DetachOwner()	{m_dwWriterTID = 0;}
#ifndef _WIN32
	unsigned long GetCurrTID(){
		return syscall(SYS_gettid);//pthread_self();
	}
#else
	DWORD GetCurrTID(){
		return ::GetCurrentThreadId();
	}
#endif
private:
	XJRWLock(const XJRWLock&);
	XJRWLock operator = (const XJRWLock&);

private:
	int m_nWaitingReaders;
	int m_nWaitingWriters;
	short m_nActive;
#ifndef _WIN32
	unsigned long m_dwWriterTID;
#else
	DWORD m_dwWriterTID;
#endif

	XJMutex		m_cs;
	XJSemaphore	m_smRead;
	XJSemaphore	m_smWrite;
private:
	bool m_OK;
};


template<class CLockObj> class XJLocalReadLock
{
public:
	XJLocalReadLock(CLockObj& obj) : m_wait(obj) {m_wait.WaitToRead();}
	~XJLocalReadLock() {m_wait.ReadDone();}
private:
	XJLocalReadLock(const XJLocalReadLock&);
	XJLocalReadLock operator = (const XJLocalReadLock&);
private:
	CLockObj& m_wait;
};

template<class CLockObj> class XJLocalWriteLock
{
public:
	XJLocalWriteLock(CLockObj& obj) : m_wait(obj) {m_wait.WaitToWrite();}
	~XJLocalWriteLock() {m_wait.WriteDone();}
private:
	XJLocalWriteLock(const XJLocalWriteLock&);
	XJLocalWriteLock operator = (const XJLocalWriteLock&);
private:
	CLockObj& m_wait;
};

typedef XJLocalReadLock<XJRWLock>		XJRWReadLock;
typedef XJLocalWriteLock<XJRWLock>		XJRWWriteLock;

} /* namespace XJUtilClass */

#endif /* XJRWLOCK_H_ */
